export type Middleware<T> = (context: T, next: Next) => Promise<any>;
export type ComposedMiddleware<T> = (context: T, next?: Next) => Promise<void>;

export type Next = () => Promise<any>;

/**
 * 利用了Promise的链式调用机制。
 * 实现了中间件的链式调用
 * @param middleware
 * @constructor
 */
export default function Compose<T>(
  middleware: Middleware<T>[]
): ComposedMiddleware<T> {
  return function(context: T, next?: Next) {
    let _index = -1;

    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    return dispatch(0);
    function dispatch(i: number): Promise<any> {
      // 一个中间件里多次调用next
      if (i <= _index)
        return Promise.reject(new Error("next() called multiple times"));
      _index = i;
      // fn就是当前的中间件
      let _fn = middleware[i];
      if (i === middleware.length) _fn = next!; // 最后一个中间件不用 next
      if (!_fn)
        return Promise.resolve(() => {
          console.log("ok");
        }); // 没有中间件，直接返回成功
      try {
        return Promise.resolve(_fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err);
      }
    }
  };
}
